<html>
<head>
<title>Prime Numbers</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body style="background-color:#000;color:#0f0;font-family:courier new;font-size:14px;">
<pre id="map">map</pre>
<script>

(function() {

	function Map(x, y) {
		var m = [];
		for (var i = 0; i < x; i++) {
			m[i] = [];
			for (var j = 0; j < y; j++) {
				m[i][j] = 0;
			}
		}
		this.sx = x;
		this.sy = y;
		this.map = m;
	}

	Map.prototype = {
		isOut : function(x, y) {
			return 0 > x || 0 > y || this.sx <= x || this.sy <= y;
		},
		get : function(x, y) {
			if (this.isOut(x, y)) return 0;
			return this.map[x][y];
		},
		around : function(x, y) {
			return (1 == this.get(x, y - 1)) + (1 == this.get(x + 1, y - 1)) +
				(1 == this.get(x + 1, y)) + (1 == this.get(x + 1, y + 1)) +
				(1 == this.get(x, y + 1)) + (1 == this.get(x - 1, y + 1)) +
				(1 == this.get(x - 1, y)) + (1 == this.get(x - 1, y - 1));
/*
			return (0 < this.get(x, y - 1)) + (0 < this.get(x + 1, y - 1)) +
			(0 < this.get(x + 1, y)) + (0 < this.get(x + 1, y + 1)) +
			(0 < this.get(x, y + 1)) + (0 < this.get(x - 1, y + 1)) +
			(0 < this.get(x - 1, y)) + (0 < this.get(x - 1, y - 1));
*/
		},
		set : function(x, y, v) {
			if (!this.isOut(x, y)) this.map[x][y] = v;
		}
	};

	function CellMap(x, y, rule) {
		this.sx = x;
		this.sy = y;
		this.map = [new Map(x, y), new Map(x, y)];
		this.now = 0;
		this.rule = rule;
	}

	CellMap.prototype = {
		isOut : function(x, y) {
			return 0 > x || 0 > y || this.sx <= x || this.sy <= y;
		},
		get : function(x, y) {
			if (this.isOut(x, y)) return 0;
			return this.map[this.now].get(x, y);
		},
		around : function(x, y) {
			return this.map[this.now].around(x, y);
		},
		set : function(x, y, v) {
			if (!this.isOut(x, y)) this.map[this.now].set(x, y, v);
		},
		next : function(f) {
			var rule = null != f ? f : this.rule;
			var n = this.map[this.now], r = this.map[1 - this.now];
			var sx = this.sx, sy = this.sy;
			for (var x = 0; x < sx; x ++) {
				for (var y = 0; y < sy; y++) {
					r.set(x, y, rule(x, y, n));
				}
			}
			this.now = 1 - this.now;
		}
	};

	var RULE_REG = new RegExp("([0-9]*)/([0-9]*)(,([0-9]+))*");

	function split(v) {
		var a = [];
		for (var i = 0; i < v.length; i++) {
			a[i] = v.charAt(i);
		}
		return a;
	}

	function state(v, s) {
		var r = [];
		var a = split(v);
		for (var i = 0; i < a.length; i++) {
			r[a[i]] = s;
		}
		return r;
	}

	var Rule = {
		create : function(rule) {
			return function(x, y, m) {
				var s = m.get(x, y);
				var c = m.around(x, y);
				var v = rule[s];
				if (null != v) {
					v = v[c];
				}
				return null == v ? 0 : v;
			};
		},
		parse : function(value) {
			var match = value.match(RULE_REG);
			var rule = [[]];
			rule[0] = state(match[1], 1);
			var count = null != match[4] ? match[4] : 2;
			for (var i = 1; i < count; i++) {
				rule[i] = state(match[2], i + (2 < count ? 1 : 0));
			}
			return Rule.create(rule);
		},
		random : function(n) {
			return function(x, y, m) {
				return parseInt(Math.random() * n);
			};
		},
		draw : function(ch) {
			return function(x, y, m) {
				return ch[m.get(x, y)];
			};
		}
	};

	function MapDrawer(e, m, rule) {
		this.e = e;
		this.map = m;
		this.rule = rule;
	}

	MapDrawer.prototype = {
		draw : function() {
			var t = "";
			var r = this.rule;
			var sx = this.map.sx, sy = this.map.sy;
			var m = this.map, c = this.ch;
			for (var y = 0; y < sy; y++) {
				for (var x = 0; x < sx; x++) {
					t += r(x, y, m);
				}
				t += "<br/>";
			}
			this.e.innerHTML = t;
		}
	};

	function CellAutomata(element, x, y, rule, ch) {
		this.map = new CellMap(x, y, rule);
		this.drawer = new MapDrawer(element, this.map, ch);
	}

	CellAutomata.prototype = {
		set : function(rule) {
			this.map.next(rule);
		},
		draw : function() {
			this.drawer.draw();
		},
		next : function(rule) {
			this.set(rule);
			this.draw();
		}
	};

	function package(package, target){
		var na = package.split(".");
		var t = window;
		for (var i in na) {
                t[na[i]] = t[na[i]] || {};
                t = t[na[i]];
		}
		for (var i in target) {
			t[i] = target[i];
		}
	}

	package("akinao.ca", {
		Rule : Rule,
		CellAutomata : CellAutomata
	});

})();


var Rule = akinao.ca.Rule;
var CA = akinao.ca.CellAutomata;

var r = Rule.random;

var g = Rule.create(
	[
	//   0  1  2  3  4  5  6  7  8
		[0, 0, 0, 1, 1, 1, 0, 0, 0],
		[0 ,0 ,0, 2, 2, 2, 0, 0, 0]
	]);

var g2 = Rule.create(
	[
	//   0  1  2  3  4  5  6  7  8
		[0, 0, 0, 0, 1, 1, 0, 0, 1],
		[2 ,2 ,1, 2, 0, 1, 1, 1, 1]
	]);

var g3 = Rule.create(
	[
	//   0  1  2  3  4  5  6  7  8
		[0, 0, 0, 0, 1, 0, 1, 1, 1],
		[0 ,0 ,0, 1, 0, 1, 1, 1, 1]
	]);

var g4 = Rule.create(
	[
	//   0  1  2  3  4  5  6  7  8
		[0, 0, 0, 1, 0, 0, 0, 0, 0],
		[2 ,2 ,3, 3, 2, 2, 2, 2, 2],
		[0, 0, 0, 1, 0, 0, 0, 0, 0],
		[2 ,2 ,3, 3, 2, 2, 2, 2, 2]
	]);

var brain = Rule.create(
		[
		//   0  1  2  3  4  5  6  7  8
			[0, 0, 1, 0, 0, 0, 0, 0, 0],
			[2 ,2 ,2, 2, 2, 2, 2, 2, 2],
			[0 ,0 ,0, 0, 0, 0, 0, 0, 0],
			[0 ,0 ,0, 0, 0, 0, 0, 0, 0],
			[0 ,0 ,0, 0, 0, 0, 0, 0, 0],
		]);

var brain6 = Rule.create(
		[
		//   0  1  2  3  4  5  6  7  8
			[0, 0, 1, 0, 1, 0, 1, 0, 0],
			[2 ,2 ,2, 2, 2, 2, 1, 2, 2],
			[3 ,3 ,3, 3, 3, 3, 2, 3, 3],
			[0 ,0 ,0, 0, 0, 0, 0, 0, 0],
			[0 ,0 ,0, 0, 0, 0, 0, 0, 0],
		]);

var starWars = Rule.create(
		[
		//   0  1  2  3  4  5  6  7  8
			[0, 0, 1, 0, 0, 0, 0, 0, 0],
			[2 ,2 ,2, 1, 1, 1, 2, 2, 2],
			[3 ,3 ,3, 2, 2, 2, 3, 3, 3],
//			[0 ,0 ,0, 3, 3, 3, 0, 0, 0],
		]);

var ch = Rule.draw([" ", "1", "2", "3", "4", "5"]);
var l = Rule.parse("2/012345678,3");
//var l = Rule.parse("3/23");

var ca = new CA(document.getElementById("map"), 96, 36, starWars, ch);

ca.next(Rule.random(1.4));

next();

function next() {
	ca.next();
	setTimeout(next, 1);
}
</script>
<a href="javascript:next();">next</a>
</body>
</html>
